<template>
  <el-icon :ref="changeRef" :class="prefixCls" v-bind="$attrs">
    <svg v-if="isLocal" :class="getSvgClass" aria-hidden="true">
      <use :xlink:href="symbolId" />
    </svg>

    <span v-else ref="elRef" :class="$attrs.class" :style="getIconifyStyle">
      <span :class="getSvgClass" :data-icon="symbolId"></span>
    </span>

    <template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
      <slot :name="name" v-bind="slotProps"></slot>
    </template>
  </el-icon>
</template>

<script setup lang="ts">
import Iconify from '@purge-icons/generated'
import { useDesign } from '@/hooks/web/useDesign'
import type { ZIconInstance, ZIconProps } from '../types'

defineOptions({ name: 'ZIcon', inheritAttrs: false })

const props = withDefaults(defineProps<ZIconProps>(), {
  // icon name
  icon: 'ep:close',
  // icon svg class
  svgClass: ''
})

const vm = getCurrentInstance()
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('icon')
const elRef = useTemplateRef<ElRef>('elRef')
const isLocal = computed(() => props.icon?.startsWith('svg-icon:')) // 是否直接使用svg图标
const symbolId = computed(() => {
  return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : props.icon
}) // 加载的svg
const getIconifyStyle = computed(() => {
  const { color, size } = props
  return {
    fontSize: `${size}px`,
    height: '1em',
    color
  }
}) // 获取Icon的样式
const getSvgClass = computed(() => {
  const { svgClass } = props
  return `iconify ${svgClass}`
}) // 获取svg类名称

// svg更新的方法
const updateIcon = async (icon: string) => {
  if (unref(isLocal)) return

  const el = unref(elRef)
  if (!el) return

  await nextTick()

  if (!icon) return

  const svg = Iconify.renderSVG(icon, {})
  if (svg) {
    el.textContent = ''
    el.appendChild(svg)
  } else {
    const span = document.createElement('span')
    span.className = 'iconify'
    span.dataset.icon = icon
    el.textContent = ''
    el.appendChild(span)
  }
}

// 监听props的icon值变化更新icon
watch(
  () => props.icon,
  (icon: string) => {
    updateIcon(icon)
  }
)

const changeRef = (IconInstance: Record<string, any> | null) => {
  if (vm) {
    vm.exposeProxy = vm.exposed = Object.assign(
      IconInstance || {},
      {} // 这里写暴露的方法
    ) as ZIconInstance
  }
}

defineExpose((vm?.exposeProxy || {}) as ZIconInstance)
</script>

<style scoped lang="scss"></style>
